Skip to content

fix: ingesting one card no longer copies every card of its type#5289

Open
jurgenwerk wants to merge 3 commits into
mainfrom
cs-11682-ingest-instance-graph
Open

fix: ingesting one card no longer copies every card of its type#5289
jurgenwerk wants to merge 3 commits into
mainfrom
cs-11682-ingest-instance-graph

Conversation

@jurgenwerk

@jurgenwerk jurgenwerk commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

What was wrong

boxel realm ingest-card <card> copies a card out of one realm into a local folder. When you pointed it at a single card instance, it copied every instance of that card's type instead of just the one you asked for — along with all the records those instances reference.

Why it matters

The software factory uses this command to pull an existing card into a workspace so an agent can adjust it. Over-copying meant every "adjust a card" run dragged in unrelated records, which then bloated the baseline tests the factory writes and runs against the copy.

What this changes

The URL you give it now means what you'd expect:

  • A single card instance → copies that instance, the code it needs, and the records it actually links to — and nothing else. Unrelated instances of the same type are left behind.
  • A card's type (its module) → unchanged: still copies every instance of that type.

Mechanically: for a single instance we now walk that card's links the same way we already walk a module's imports, instead of running a blanket "find everything of this type" search.

Testing

  • Real factory run: ingesting one card instance now copies that instance + only the records it links to (before: every instance of the type, plus everything they referenced).
  • Unit tests: parsing a card's links, and a fake-realm ingest that copies the entry instance + its linked records while leaving an unrelated sibling instance behind.

Note for reviewers

Builds on #5276 — without that change the card's catalog Spec isn't copied when the source realm is a shared/published one (a separate fix). The two land together.

…k graph

An instance URL meant "this record" but ingest-card swept in every instance of
the entry card's type (findEntryInstances searches `type: {module,name}`
regardless of entry kind) — so ingesting one WineCellar pulled both cellars +
all 8 bottles. A module URL still means "the card type."

Branch on entry kind in sync(): for an instance entry, crawl the same-realm
link graph from that instance (`linksTo`/`linksToMany` via relationship
`links.self`, transitively) — the instance analogue of crawlModules — instead
of the type-wide instance sweep. Module entries are unchanged.

Verified live: ingesting one catalog WineCellar instance now copies that cellar
+ its 6 linked bottles (was both cellars + all 8). New unit tests:
extractRelationshipLinks parsing + a fake-realm instance ingest that excludes
unrelated siblings.

CS-11682. Stacks on CS-11652 (per-realm _search) for Spec copying.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes boxel realm ingest-card <instance-url> so an instance entry copies only that specific record’s same-realm link graph (plus its module deps), instead of copying all instances of the card type.

Changes:

  • Add extractRelationshipLinks() and instance-link crawling (crawlInstanceLinks) to ingest same-realm relationships.*.links.self targets transitively when the entry is an instance URL.
  • Keep module-entry behavior unchanged (module URL still means “the type” → ingest all instances of that type).
  • Add helper-unit coverage for relationship link extraction and a new integration-style fixture test for instance ingestion.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/boxel-cli/src/commands/realm/ingest-card.ts Adds relationship-link extraction + BFS crawling for instance entries; branches ingest behavior based on entry kind.
packages/boxel-cli/tests/commands/ingest-card.test.ts Adds unit tests for extractRelationshipLinks().
packages/boxel-cli/tests/commands/ingest-card-instance.test.ts Adds fixture-based test ensuring instance ingest includes only the entry + linked records (not unrelated siblings).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +387 to +392
let rel =
/^https?:\/\//.test(self) || self.startsWith('@')
? this.relativize(self)
: this.relativize(new URL(self, this.relToAbs(fromRel)).href);
let candidate = rel.endsWith('.json') ? rel : `${rel}.json`;
return fileSet.has(candidate) ? candidate : null;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Written by Claude on Matic's behalf.)

Fixed in da9762f. resolveLinkedInstanceRel now resolves relative/absolute http(s) links to an absolute URL and requires startsWith(this.realmRoot) — a link into another realm (even one whose URL shares our path tail) returns null and is left as a runtime reference, mirroring resolveSameRealmFile. The published-alias @cardstack/<realm>/… form still maps by the realm tail. Added a regression case: the instance fixture's entry card now carries a decoy link to a different host with the same /garage/ tail pointing at a locally-existing path, and the test asserts it's not copied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jurgenwerk jurgenwerk changed the title fix: ingest-card from an instance URL copies only that instance's link graph fix: ingesting one card no longer copies every card of its type Jun 19, 2026
resolveLinkedInstanceRel passed absolute http(s) links through relativize(),
whose path-tail fallback could match another realm whose URL happens to share
this realm's tail (e.g. a different host's /garage/), wrongly copying a local
file. Require a resolved relative/absolute link to live under this realm's
served root (mirrors resolveSameRealmFile); the published-alias (@cardstack/…)
form still maps by tail. Adds a cross-realm decoy link to the instance test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jurgenwerk jurgenwerk marked this pull request as ready for review June 19, 2026 11:37
@jurgenwerk jurgenwerk requested a review from a team June 19, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants